gh-139103: Use borrowed references for positional args in _PyStack_UnpackDict#144407
Conversation
…ack_UnpackDict The positional arguments passed to _PyStack_UnpackDict are already kept alive by the caller, so we can avoid the extra reference count operations by using borrowed references instead of creating new ones. This reduces reference count contention in the free-threaded build when calling functions with keyword arguments. In particular, this avoids contention on the type argument to `__new__` when instantiating namedtuples with keyword arguments.
vstinner
left a comment
There was a problem hiding this comment.
LGTM.
The positional arguments are borrowed references from the input array
(which must be kept alive by the caller). The keyword argument values
are new references.
IMO it's a reasonable assumption. If there are bugs, the caller should be modified to hold a strong reference to its arguments.
_PyStack_UnpackDict() callers:
- _PyObject_VectorcallDictTstate():
PyObject *const *args - _PyVectorcall_Call():
PyObject *tuple - _PyEvalFramePushAndInit_Ex():
PyObject *callargs(tuple)
_PyObject_VectorcallDictTstate() callers:
- PyObject_VectorcallDict():
PyObject *const *args - PyEval_CallObjectWithKeywords(): pass
NULLfor args - _PyObject_Call_Prepend():
PyObject *args(tuple)
Most calls take their positional arguments from a tuple (safe). The most risky code path are calls to PyObject_VectorcallDict(): the change makes the assumption that this function is only called with strong references.
FWIW, Lines 133 to 136 in 29acc08 |
The positional arguments passed to _PyStack_UnpackDict are already kept alive by the caller, so we can avoid the extra reference count operations by using borrowed references instead of creating new ones.
This reduces reference count contention in the free-threaded build when calling functions with keyword arguments. In particular, this avoids contention on the type argument to
__new__when instantiating namedtuples with keyword arguments.